//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <ddk.h>
#include <display.h>

#define LCD_WIDTH                   240
#define LCD_HEIGHT                  320
#define PIXELBYTES                  2
#define PIXELBITS                   16          // Bits per pixel
#define LCD_BUFFERSIZE              64 * 4096
#define LCDPIXELS                   (UInt32)(LCD_WIDTH * LCD_HEIGHT)
#define LCD_LINERAPIXEL(_x_,_y_)    (UInt32)( (_y_) * LCD_WIDTH + (_x_) )
#define LCDPIXELTOBYTE(_x_,_y_)     (UInt32)( LcdLinearPixel((_x_),(_y_)) * PIXELBYTES)

//class declare
class CDisplay : public CDeviceDriver
{
public:
    CARAPI Read(
                    /* [in] */ Int64 u64Offset,
                    /* [in] */ Int32 bytesToRead,
                    /* [out] */ MemoryBuf * pBuffer,
                    /* [out] */ IEvent * * ppCompletionEvent);
    CARAPI Write(
                    /* [in] */ Int64 u64Offset,
                    /* [in] */ const MemoryBuf & buffer,
                    /* [out] */ Int32 * pBytesWritten,
                    /* [out] */ IEvent * * ppCompletionEvent);
    CARAPI Control(
                    /* [in] */ Handle32 nControlCode,
                    /* [in] */ const MemoryBuf & inBuffer,
                    /* [out] */ MemoryBuf * pOutBuffer,
                    /* [out] */ IEvent * * ppCompletionEvent);

    virtual void Dispose();
};

ECode CDisplay::Read(
                /* [in] */ Int64 u64Offset,
                /* [in] */ Int32 bytesToRead,
                /* [out] */ MemoryBuf * pBuffer,
                /* [out] */ IEvent * * ppCompletionEvent)
{
    return E_NOT_IMPLEMENTED;
}

ECode CDisplay::Write(
                /* [in] */ Int64 u64Offset,
                /* [in] */ const MemoryBuf & buffer,
                /* [out] */ Int32 * pBytesWritten,
                /* [out] */ IEvent * * ppCompletionEvent)
{
    return E_NOT_IMPLEMENTED;
}

EXTERN_C physaddr_t LCDPhysAddr;
EXTERN_C Address LCDVirAddr;
Address LCDVirAddr;

ECode CDisplay::Control(
                /* [in] */ Handle32 nControlCode,
                /* [in] */ const MemoryBuf & inBuffer,
                /* [out] */ MemoryBuf * pOutBuffer,
                /* [out] */ IEvent * * ppCompletionEvent)
{
    UInt32 DisplayMode = (UInt32)nControlCode;
    char *tBuf = NULL;
    ECode ec = NOERROR;
    FrameBufferFormat fbFormat;

    switch (DisplayMode) {
        case 0:
            break;

        case 1 : //get frame buffer physical address
            break;

        case 3 : //Get frame buffer virtual address
            assert(pOutBuffer && pOutBuffer->GetPayload());
            tBuf = (char *)pOutBuffer->GetPayload();
            ec = DzIoRemap(0, LCD_BUFFERSIZE, LCDPhysAddr,
                            0, MemoryProtection_RW | IoRemapFlag_BufferedWrite,
                            &LCDVirAddr);
            if (FAILED(ec)) {
                kprintf("IoRemap Display Base Address Failed!, ec is 0x%08x\n", ec);
                return ec;
            }
            ((UInt32*)tBuf)[0] = (UInt32)LCDVirAddr;
            pOutBuffer->SetUsed(sizeof(UInt32));
            Outl(0x8e000000, LCDPhysAddr);
            break;

        case 7: // Get FrameBuffe rFormat
            assert(pOutBuffer && pOutBuffer->GetPayload());
            fbFormat.Color = COLOR_RGB565;
            fbFormat.Bpp = PIXELBITS;        // Bits per pixel
            fbFormat.Width = LCD_WIDTH;
            fbFormat.Height = LCD_HEIGHT;
            pOutBuffer->Copy((Byte *)&fbFormat, sizeof(FrameBufferFormat));
            break;

        case 10:
            break;

        case 11:
            break;

        default :
            break;
    }
    return ec;
}

void CDisplay::Dispose()
{
}

physaddr_t LCDPhysAddr;

static Boolean IOLCDInit()
{
    LCDPhysAddr = DzAllocPages(6, 0);
    if (LCDPhysAddr == INVALID_PAGE_ADDRESS) {
        kprintf("IOLCDInit, DzAllocPages Fail \n");
        return FALSE;
    }
    return TRUE;
}

EXTERN IDeviceDriver * CDECL CreateDisplay(uint_t uDeviceNo, void *pvParameter)
{
    IDeviceDriver *pDriver;

    pDriver = new CDisplay();
    if (NULL == pDriver) return NULL;
    pDriver->AddRef();
    if (!IOLCDInit()) {
        pDriver->Release();
        return NULL;
    }

    return pDriver;
}
